home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / Chapter 14 The Tessellation Stages / BezierPatch / BezierPatchApp.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2016-03-02  |  30.0 KB  |  842 lines

  1. //***************************************************************************************
  2. // BezierPatchApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
  3. //***************************************************************************************
  4.  
  5. #include "../../Common/d3dApp.h"
  6. #include "../../Common/MathHelper.h"
  7. #include "../../Common/UploadBuffer.h"
  8. #include "../../Common/GeometryGenerator.h"
  9. #include "FrameResource.h"
  10.  
  11. using Microsoft::WRL::ComPtr;
  12. using namespace DirectX;
  13. using namespace DirectX::PackedVector;
  14.  
  15. #pragma comment(lib, "d3dcompiler.lib")
  16. #pragma comment(lib, "D3D12.lib")
  17.  
  18. const int gNumFrameResources = 3;
  19.  
  20. // Lightweight structure stores parameters to draw a shape.  This will
  21. // vary from app-to-app.
  22. struct RenderItem
  23. {
  24.     RenderItem() = default;
  25.  
  26.     // World matrix of the shape that describes the object's local space
  27.     // relative to the world space, which defines the position, orientation,
  28.     // and scale of the object in the world.
  29.     XMFLOAT4X4 World = MathHelper::Identity4x4();
  30.  
  31.     XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
  32.  
  33.     // Dirty flag indicating the object data has changed and we need to update the constant buffer.
  34.     // Because we have an object cbuffer for each FrameResource, we have to apply the
  35.     // update to each FrameResource.  Thus, when we modify obect data we should set 
  36.     // NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
  37.     int NumFramesDirty = gNumFrameResources;
  38.  
  39.     // Index into GPU constant buffer corresponding to the ObjectCB for this render item.
  40.     UINT ObjCBIndex = -1;
  41.  
  42.     Material* Mat = nullptr;
  43.     MeshGeometry* Geo = nullptr;
  44.  
  45.     // Primitive topology.
  46.     D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  47.  
  48.     // DrawIndexedInstanced parameters.
  49.     UINT IndexCount = 0;
  50.     UINT StartIndexLocation = 0;
  51.     int BaseVertexLocation = 0;
  52. };
  53.  
  54. enum class RenderLayer : int
  55. {
  56.     Opaque = 0,
  57.     Count
  58. };
  59.  
  60. class BezierPatchApp : public D3DApp
  61. {
  62. public:
  63.     BezierPatchApp(HINSTANCE hInstance);
  64.     BezierPatchApp(const BezierPatchApp& rhs) = delete;
  65.     BezierPatchApp& operator=(const BezierPatchApp& rhs) = delete;
  66.     ~BezierPatchApp();
  67.  
  68.     virtual bool Initialize()override;
  69.  
  70. private:
  71.     virtual void OnResize()override;
  72.     virtual void Update(const GameTimer& gt)override;
  73.     virtual void Draw(const GameTimer& gt)override;
  74.  
  75.     virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
  76.     virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
  77.     virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
  78.  
  79.     void OnKeyboardInput(const GameTimer& gt);
  80.     void UpdateCamera(const GameTimer& gt);
  81.     void AnimateMaterials(const GameTimer& gt);
  82.     void UpdateObjectCBs(const GameTimer& gt);
  83.     void UpdateMaterialCBs(const GameTimer& gt);
  84.     void UpdateMainPassCB(const GameTimer& gt);
  85.  
  86.     void LoadTextures();
  87.     void BuildRootSignature();
  88.     void BuildDescriptorHeaps();
  89.     void BuildShadersAndInputLayout();
  90.     void BuildQuadPatchGeometry();
  91.     void BuildPSOs();
  92.     void BuildFrameResources();
  93.     void BuildMaterials();
  94.     void BuildRenderItems();
  95.     void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
  96.  
  97.     std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> GetStaticSamplers();
  98.  
  99. private:
  100.  
  101.     std::vector<std::unique_ptr<FrameResource>> mFrameResources;
  102.     FrameResource* mCurrFrameResource = nullptr;
  103.     int mCurrFrameResourceIndex = 0;
  104.  
  105.     UINT mCbvSrvDescriptorSize = 0;
  106.  
  107.     ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
  108.  
  109.     ComPtr<ID3D12DescriptorHeap> mSrvDescriptorHeap = nullptr;
  110.  
  111.     std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
  112.     std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
  113.     std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;
  114.     std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
  115.     std::unordered_map<std::string, ComPtr<ID3D12PipelineState>> mPSOs;
  116.  
  117.     std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
  118.  
  119.     // Cache render items of interest.
  120.     RenderItem* mSkullRitem = nullptr;
  121.     RenderItem* mReflectedSkullRitem = nullptr;
  122.     RenderItem* mShadowedSkullRitem = nullptr;
  123.  
  124.     // List of all the render items.
  125.     std::vector<std::unique_ptr<RenderItem>> mAllRitems;
  126.  
  127.     // Render items divided by PSO.
  128.     std::vector<RenderItem*> mRitemLayer[(int)RenderLayer::Count];
  129.  
  130.     PassConstants mMainPassCB;
  131.     PassConstants mReflectedPassCB;
  132.  
  133.     XMFLOAT3 mSkullTranslation = { 0.0f, 1.0f, -5.0f };
  134.  
  135.     XMFLOAT3 mEyePos = { 0.0f, 0.0f, 0.0f };
  136.     XMFLOAT4X4 mView = MathHelper::Identity4x4();
  137.     XMFLOAT4X4 mProj = MathHelper::Identity4x4();
  138.  
  139.     float mTheta = 1.24f*XM_PI;
  140.     float mPhi = 0.42f*XM_PI;
  141.     float mRadius = 12.0f;
  142.  
  143.     POINT mLastMousePos;
  144. };
  145.  
  146. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
  147.     PSTR cmdLine, int showCmd)
  148. {
  149.     // Enable run-time memory check for debug builds.
  150. #if defined(DEBUG) | defined(_DEBUG)
  151.     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  152. #endif
  153.  
  154.     try
  155.     {
  156.         BezierPatchApp theApp(hInstance);
  157.         if(!theApp.Initialize())
  158.             return 0;
  159.  
  160.         return theApp.Run();
  161.     }
  162.     catch(DxException& e)
  163.     {
  164.         MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
  165.         return 0;
  166.     }
  167. }
  168.  
  169. BezierPatchApp::BezierPatchApp(HINSTANCE hInstance)
  170.     : D3DApp(hInstance)
  171. {
  172. }
  173.  
  174. BezierPatchApp::~BezierPatchApp()
  175. {
  176.     if(md3dDevice != nullptr)
  177.         FlushCommandQueue();
  178. }
  179.  
  180. bool BezierPatchApp::Initialize()
  181. {
  182.     if(!D3DApp::Initialize())
  183.         return false;
  184.  
  185.     // Reset the command list to prep for initialization commands.
  186.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
  187.  
  188.     // Get the increment size of a descriptor in this heap type.  This is hardware specific, 
  189.     // so we have to query this information.
  190.     mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  191.  
  192.     LoadTextures();
  193.     BuildRootSignature();
  194.     BuildDescriptorHeaps();
  195.     BuildShadersAndInputLayout();
  196.     BuildQuadPatchGeometry();
  197.     BuildMaterials();
  198.     BuildRenderItems();
  199.     BuildFrameResources();
  200.     BuildPSOs();
  201.  
  202.     // Execute the initialization commands.
  203.     ThrowIfFailed(mCommandList->Close());
  204.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  205.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  206.  
  207.     // Wait until initialization is complete.
  208.     FlushCommandQueue();
  209.  
  210.     return true;
  211. }
  212.  
  213. void BezierPatchApp::OnResize()
  214. {
  215.     D3DApp::OnResize();
  216.  
  217.     // The window resized, so update the aspect ratio and recompute the projection matrix.
  218.     XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
  219.     XMStoreFloat4x4(&mProj, P);
  220. }
  221.  
  222. void BezierPatchApp::Update(const GameTimer& gt)
  223. {
  224.     OnKeyboardInput(gt);
  225.     UpdateCamera(gt);
  226.  
  227.     // Cycle through the circular frame resource array.
  228.     mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
  229.     mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
  230.  
  231.     // Has the GPU finished processing the commands of the current frame resource?
  232.     // If not, wait until the GPU has completed commands up to this fence point.
  233.     if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
  234.     {
  235.         HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
  236.         ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
  237.         WaitForSingleObject(eventHandle, INFINITE);
  238.         CloseHandle(eventHandle);
  239.     }
  240.  
  241.     AnimateMaterials(gt);
  242.     UpdateObjectCBs(gt);
  243.     UpdateMaterialCBs(gt);
  244.     UpdateMainPassCB(gt);
  245. }
  246.  
  247. void BezierPatchApp::Draw(const GameTimer& gt)
  248. {
  249.     auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
  250.  
  251.     // Reuse the memory associated with command recording.
  252.     // We can only reset when the associated command lists have finished execution on the GPU.
  253.     ThrowIfFailed(cmdListAlloc->Reset());
  254.  
  255.     // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
  256.     // Reusing the command list reuses memory.
  257.     ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
  258.  
  259.     mCommandList->RSSetViewports(1, &mScreenViewport);
  260.     mCommandList->RSSetScissorRects(1, &mScissorRect);
  261.  
  262.     // Indicate a state transition on the resource usage.
  263.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  264.         D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  265.  
  266.     // Clear the back buffer and depth buffer.
  267.     mCommandList->ClearRenderTargetView(CurrentBackBufferView(), (float*)&mMainPassCB.FogColor, 0, nullptr);
  268.     mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
  269.  
  270.     // Specify the buffers we are going to render to.
  271.     mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
  272.  
  273.     ID3D12DescriptorHeap* descriptorHeaps[] = { mSrvDescriptorHeap.Get() };
  274.     mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
  275.  
  276.     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
  277.  
  278.     UINT passCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(PassConstants));
  279.  
  280.     auto passCB = mCurrFrameResource->PassCB->Resource();
  281.     mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
  282.     
  283.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Opaque]);
  284.         
  285.     // Indicate a state transition on the resource usage.
  286.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  287.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  288.  
  289.     // Done recording commands.
  290.     ThrowIfFailed(mCommandList->Close());
  291.  
  292.     // Add the command list to the queue for execution.
  293.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  294.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  295.  
  296.     // Swap the back and front buffers
  297.     ThrowIfFailed(mSwapChain->Present(0, 0));
  298.     mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
  299.  
  300.     // Advance the fence value to mark commands up to this fence point.
  301.     mCurrFrameResource->Fence = ++mCurrentFence;
  302.  
  303.     // Add an instruction to the command queue to set a new fence point. 
  304.     // Because we are on the GPU timeline, the new fence point won't be 
  305.     // set until the GPU finishes processing all the commands prior to this Signal().
  306.     mCommandQueue->Signal(mFence.Get(), mCurrentFence);
  307. }
  308.  
  309. void BezierPatchApp::OnMouseDown(WPARAM btnState, int x, int y)
  310. {
  311.     mLastMousePos.x = x;
  312.     mLastMousePos.y = y;
  313.  
  314.     SetCapture(mhMainWnd);
  315. }
  316.  
  317. void BezierPatchApp::OnMouseUp(WPARAM btnState, int x, int y)
  318. {
  319.     ReleaseCapture();
  320. }
  321.  
  322. void BezierPatchApp::OnMouseMove(WPARAM btnState, int x, int y)
  323. {
  324.     if((btnState & MK_LBUTTON) != 0)
  325.     {
  326.         // Make each pixel correspond to a quarter of a degree.
  327.         float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
  328.         float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
  329.  
  330.         // Update angles based on input to orbit camera around box.
  331.         mTheta += dx;
  332.         mPhi += dy;
  333.  
  334.         // Restrict the angle mPhi.
  335.         mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
  336.     }
  337.     else if((btnState & MK_RBUTTON) != 0)
  338.     {
  339.         // Make each pixel correspond to 0.2 unit in the scene.
  340.         float dx = 0.2f*static_cast<float>(x - mLastMousePos.x);
  341.         float dy = 0.2f*static_cast<float>(y - mLastMousePos.y);
  342.  
  343.         // Update the camera radius based on input.
  344.         mRadius += dx - dy;
  345.  
  346.         // Restrict the radius.
  347.         mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
  348.     }
  349.  
  350.     mLastMousePos.x = x;
  351.     mLastMousePos.y = y;
  352. }
  353.  
  354. void BezierPatchApp::OnKeyboardInput(const GameTimer& gt)
  355. {
  356. }
  357.  
  358. void BezierPatchApp::UpdateCamera(const GameTimer& gt)
  359. {
  360.     // Convert Spherical to Cartesian coordinates.
  361.     mEyePos.x = mRadius*sinf(mPhi)*cosf(mTheta);
  362.     mEyePos.z = mRadius*sinf(mPhi)*sinf(mTheta);
  363.     mEyePos.y = mRadius*cosf(mPhi);
  364.  
  365.     // Build the view matrix.
  366.     XMVECTOR pos = XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
  367.     XMVECTOR target = XMVectorZero();
  368.     XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
  369.  
  370.     XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
  371.     XMStoreFloat4x4(&mView, view);
  372. }
  373.  
  374. void BezierPatchApp::AnimateMaterials(const GameTimer& gt)
  375. {
  376.  
  377. }
  378.  
  379. void BezierPatchApp::UpdateObjectCBs(const GameTimer& gt)
  380. {
  381.     auto currObjectCB = mCurrFrameResource->ObjectCB.get();
  382.     for(auto& e : mAllRitems)
  383.     {
  384.         // Only update the cbuffer data if the constants have changed.  
  385.         // This needs to be tracked per frame resource.
  386.         if(e->NumFramesDirty > 0)
  387.         {
  388.             XMMATRIX world = XMLoadFloat4x4(&e->World);
  389.             XMMATRIX texTransform = XMLoadFloat4x4(&e->TexTransform);
  390.  
  391.             ObjectConstants objConstants;
  392.             XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
  393.             XMStoreFloat4x4(&objConstants.TexTransform, XMMatrixTranspose(texTransform));
  394.  
  395.             currObjectCB->CopyData(e->ObjCBIndex, objConstants);
  396.  
  397.             // Next FrameResource need to be updated too.
  398.             e->NumFramesDirty--;
  399.         }
  400.     }
  401. }
  402.  
  403. void BezierPatchApp::UpdateMaterialCBs(const GameTimer& gt)
  404. {
  405.     auto currMaterialCB = mCurrFrameResource->MaterialCB.get();
  406.     for(auto& e : mMaterials)
  407.     {
  408.         // Only update the cbuffer data if the constants have changed.  If the cbuffer
  409.         // data changes, it needs to be updated for each FrameResource.
  410.         Material* mat = e.second.get();
  411.         if(mat->NumFramesDirty > 0)
  412.         {
  413.             XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);
  414.  
  415.             MaterialConstants matConstants;
  416.             matConstants.DiffuseAlbedo = mat->DiffuseAlbedo;
  417.             matConstants.FresnelR0 = mat->FresnelR0;
  418.             matConstants.Roughness = mat->Roughness;
  419.             XMStoreFloat4x4(&matConstants.MatTransform, XMMatrixTranspose(matTransform));
  420.  
  421.             currMaterialCB->CopyData(mat->MatCBIndex, matConstants);
  422.  
  423.             // Next FrameResource need to be updated too.
  424.             mat->NumFramesDirty--;
  425.         }
  426.     }
  427. }
  428.  
  429. void BezierPatchApp::UpdateMainPassCB(const GameTimer& gt)
  430. {
  431.     XMMATRIX view = XMLoadFloat4x4(&mView);
  432.     XMMATRIX proj = XMLoadFloat4x4(&mProj);
  433.  
  434.     XMMATRIX viewProj = XMMatrixMultiply(view, proj);
  435.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
  436.     XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
  437.     XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
  438.  
  439.     XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
  440.     XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
  441.     XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
  442.     XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
  443.     XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
  444.     XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
  445.     mMainPassCB.EyePosW = mEyePos;
  446.     mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
  447.     mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
  448.     mMainPassCB.NearZ = 1.0f;
  449.     mMainPassCB.FarZ = 1000.0f;
  450.     mMainPassCB.TotalTime = gt.TotalTime();
  451.     mMainPassCB.DeltaTime = gt.DeltaTime();
  452.     mMainPassCB.AmbientLight = { 0.25f, 0.25f, 0.35f, 1.0f };
  453.     mMainPassCB.Lights[0].Direction = { 0.57735f, -0.57735f, 0.57735f };
  454.     mMainPassCB.Lights[0].Strength = { 0.6f, 0.6f, 0.6f };
  455.     mMainPassCB.Lights[1].Direction = { -0.57735f, -0.57735f, 0.57735f };
  456.     mMainPassCB.Lights[1].Strength = { 0.3f, 0.3f, 0.3f };
  457.     mMainPassCB.Lights[2].Direction = { 0.0f, -0.707f, -0.707f };
  458.     mMainPassCB.Lights[2].Strength = { 0.15f, 0.15f, 0.15f };
  459.  
  460.     // Main pass stored in index 2
  461.     auto currPassCB = mCurrFrameResource->PassCB.get();
  462.     currPassCB->CopyData(0, mMainPassCB);
  463. }
  464.  
  465. void BezierPatchApp::LoadTextures()
  466. {
  467.     auto bricksTex = std::make_unique<Texture>();
  468.     bricksTex->Name = "bricksTex";
  469.     bricksTex->Filename = L"../../Textures/bricks.dds";
  470.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  471.         mCommandList.Get(), bricksTex->Filename.c_str(),
  472.         bricksTex->Resource, bricksTex->UploadHeap));
  473.  
  474.     auto checkboardTex = std::make_unique<Texture>();
  475.     checkboardTex->Name = "checkboardTex";
  476.     checkboardTex->Filename = L"../../Textures/checkboard.dds";
  477.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  478.         mCommandList.Get(), checkboardTex->Filename.c_str(),
  479.         checkboardTex->Resource, checkboardTex->UploadHeap));
  480.  
  481.     auto iceTex = std::make_unique<Texture>();
  482.     iceTex->Name = "iceTex";
  483.     iceTex->Filename = L"../../Textures/ice.dds";
  484.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  485.         mCommandList.Get(), iceTex->Filename.c_str(),
  486.         iceTex->Resource, iceTex->UploadHeap));
  487.  
  488.     auto white1x1Tex = std::make_unique<Texture>();
  489.     white1x1Tex->Name = "white1x1Tex";
  490.     white1x1Tex->Filename = L"../../Textures/white1x1.dds";
  491.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  492.         mCommandList.Get(), white1x1Tex->Filename.c_str(),
  493.         white1x1Tex->Resource, white1x1Tex->UploadHeap));
  494.  
  495.     mTextures[bricksTex->Name] = std::move(bricksTex);
  496.     mTextures[checkboardTex->Name] = std::move(checkboardTex);
  497.     mTextures[iceTex->Name] = std::move(iceTex);
  498.     mTextures[white1x1Tex->Name] = std::move(white1x1Tex);
  499. }
  500.  
  501. void BezierPatchApp::BuildRootSignature()
  502. {
  503.     CD3DX12_DESCRIPTOR_RANGE texTable;
  504.     texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
  505.  
  506.     // Root parameter can be a table, root descriptor or root constants.
  507.     CD3DX12_ROOT_PARAMETER slotRootParameter[4];
  508.  
  509.     // Perfomance TIP: Order from most frequent to least frequent.
  510.     slotRootParameter[0].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_PIXEL);
  511.     slotRootParameter[1].InitAsConstantBufferView(0);
  512.     slotRootParameter[2].InitAsConstantBufferView(1);
  513.     slotRootParameter[3].InitAsConstantBufferView(2);
  514.  
  515.     auto staticSamplers = GetStaticSamplers();
  516.  
  517.     // A root signature is an array of root parameters.
  518.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(4, slotRootParameter,
  519.         (UINT)staticSamplers.size(), staticSamplers.data(),
  520.         D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  521.  
  522.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  523.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  524.     ComPtr<ID3DBlob> errorBlob = nullptr;
  525.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  526.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  527.  
  528.     if(errorBlob != nullptr)
  529.     {
  530.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  531.     }
  532.     ThrowIfFailed(hr);
  533.  
  534.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  535.         0,
  536.         serializedRootSig->GetBufferPointer(),
  537.         serializedRootSig->GetBufferSize(),
  538.         IID_PPV_ARGS(mRootSignature.GetAddressOf())));
  539. }
  540.  
  541. void BezierPatchApp::BuildDescriptorHeaps()
  542. {
  543.     //
  544.     // Create the SRV heap.
  545.     //
  546.     D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
  547.     srvHeapDesc.NumDescriptors = 4;
  548.     srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  549.     srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  550.     ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));
  551.  
  552.     //
  553.     // Fill out the heap with actual descriptors.
  554.     //
  555.     CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
  556.  
  557.     auto bricksTex = mTextures["bricksTex"]->Resource;
  558.     auto checkboardTex = mTextures["checkboardTex"]->Resource;
  559.     auto iceTex = mTextures["iceTex"]->Resource;
  560.     auto white1x1Tex = mTextures["white1x1Tex"]->Resource;
  561.  
  562.     D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  563.     srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  564.     srvDesc.Format = bricksTex->GetDesc().Format;
  565.     srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  566.     srvDesc.Texture2D.MostDetailedMip = 0;
  567.     srvDesc.Texture2D.MipLevels = -1;
  568.     md3dDevice->CreateShaderResourceView(bricksTex.Get(), &srvDesc, hDescriptor);
  569.  
  570.     // next descriptor
  571.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  572.  
  573.     srvDesc.Format = checkboardTex->GetDesc().Format;
  574.     md3dDevice->CreateShaderResourceView(checkboardTex.Get(), &srvDesc, hDescriptor);
  575.  
  576.     // next descriptor
  577.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  578.  
  579.     srvDesc.Format = iceTex->GetDesc().Format;
  580.     md3dDevice->CreateShaderResourceView(iceTex.Get(), &srvDesc, hDescriptor);
  581.  
  582.     // next descriptor
  583.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  584.  
  585.     srvDesc.Format = white1x1Tex->GetDesc().Format;
  586.     md3dDevice->CreateShaderResourceView(white1x1Tex.Get(), &srvDesc, hDescriptor);
  587. }
  588.  
  589. void BezierPatchApp::BuildShadersAndInputLayout()
  590. {
  591.     mShaders["tessVS"] = d3dUtil::CompileShader(L"Shaders\\BezierTessellation.hlsl", nullptr, "VS", "vs_5_0");
  592.     mShaders["tessHS"] = d3dUtil::CompileShader(L"Shaders\\BezierTessellation.hlsl", nullptr, "HS", "hs_5_0");
  593.     mShaders["tessDS"] = d3dUtil::CompileShader(L"Shaders\\BezierTessellation.hlsl", nullptr, "DS", "ds_5_0");
  594.     mShaders["tessPS"] = d3dUtil::CompileShader(L"Shaders\\BezierTessellation.hlsl", nullptr, "PS", "ps_5_0");
  595.     
  596.     mInputLayout =
  597.     {
  598.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
  599.     };
  600. }
  601.  
  602. void BezierPatchApp::BuildQuadPatchGeometry()
  603. {
  604.     std::array<XMFLOAT3,16> vertices =
  605.     {
  606.         // Row 0
  607.         XMFLOAT3(-10.0f, -10.0f, +15.0f),
  608.         XMFLOAT3(-5.0f,  0.0f, +15.0f),
  609.         XMFLOAT3(+5.0f,  0.0f, +15.0f),
  610.         XMFLOAT3(+10.0f, 0.0f, +15.0f),
  611.  
  612.         // Row 1
  613.         XMFLOAT3(-15.0f, 0.0f, +5.0f),
  614.         XMFLOAT3(-5.0f,  0.0f, +5.0f),
  615.         XMFLOAT3(+5.0f,  20.0f, +5.0f),
  616.         XMFLOAT3(+15.0f, 0.0f, +5.0f),
  617.  
  618.         // Row 2
  619.         XMFLOAT3(-15.0f, 0.0f, -5.0f),
  620.         XMFLOAT3(-5.0f,  0.0f, -5.0f),
  621.         XMFLOAT3(+5.0f,  0.0f, -5.0f),
  622.         XMFLOAT3(+15.0f, 0.0f, -5.0f),
  623.  
  624.         // Row 3
  625.         XMFLOAT3(-10.0f, 10.0f, -15.0f),
  626.         XMFLOAT3(-5.0f,  0.0f, -15.0f),
  627.         XMFLOAT3(+5.0f,  0.0f, -15.0f),
  628.         XMFLOAT3(+25.0f, 10.0f, -15.0f)
  629.     };
  630.  
  631.     std::array<std::int16_t, 16> indices = 
  632.     { 
  633.         0, 1, 2, 3,
  634.         4, 5, 6, 7,
  635.         8, 9, 10, 11, 
  636.         12, 13, 14, 15
  637.     };
  638.  
  639.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  640.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
  641.  
  642.     auto geo = std::make_unique<MeshGeometry>();
  643.     geo->Name = "quadpatchGeo";
  644.  
  645.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  646.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  647.  
  648.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  649.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  650.  
  651.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  652.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  653.  
  654.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  655.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  656.  
  657.     geo->VertexByteStride = sizeof(XMFLOAT3);
  658.     geo->VertexBufferByteSize = vbByteSize;
  659.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  660.     geo->IndexBufferByteSize = ibByteSize;
  661.  
  662.     SubmeshGeometry quadSubmesh;
  663.     quadSubmesh.IndexCount = (UINT)indices.size();
  664.     quadSubmesh.StartIndexLocation = 0;
  665.     quadSubmesh.BaseVertexLocation = 0;
  666.  
  667.     geo->DrawArgs["quadpatch"] = quadSubmesh;
  668.  
  669.     mGeometries[geo->Name] = std::move(geo);
  670. }
  671.  
  672. void BezierPatchApp::BuildPSOs()
  673. {
  674.     D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
  675.  
  676.     //
  677.     // PSO for opaque objects.
  678.     //
  679.     ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  680.     opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
  681.     opaquePsoDesc.pRootSignature = mRootSignature.Get();
  682.     opaquePsoDesc.VS = 
  683.     { 
  684.         reinterpret_cast<BYTE*>(mShaders["tessVS"]->GetBufferPointer()), 
  685.         mShaders["tessVS"]->GetBufferSize()
  686.     };
  687.     opaquePsoDesc.HS =
  688.     {
  689.         reinterpret_cast<BYTE*>(mShaders["tessHS"]->GetBufferPointer()),
  690.         mShaders["tessHS"]->GetBufferSize()
  691.     };
  692.     opaquePsoDesc.DS =
  693.     {
  694.         reinterpret_cast<BYTE*>(mShaders["tessDS"]->GetBufferPointer()),
  695.         mShaders["tessDS"]->GetBufferSize()
  696.     };
  697.     opaquePsoDesc.PS = 
  698.     { 
  699.         reinterpret_cast<BYTE*>(mShaders["tessPS"]->GetBufferPointer()),
  700.         mShaders["tessPS"]->GetBufferSize()
  701.     };
  702.     opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  703.     opaquePsoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;
  704.     opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  705.     opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  706.     opaquePsoDesc.SampleMask = UINT_MAX;
  707.     opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
  708.     opaquePsoDesc.NumRenderTargets = 1;
  709.     opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
  710.     opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  711.     opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  712.     opaquePsoDesc.DSVFormat = mDepthStencilFormat;
  713.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
  714. }
  715.  
  716. void BezierPatchApp::BuildFrameResources()
  717. {
  718.     for(int i = 0; i < gNumFrameResources; ++i)
  719.     {
  720.         mFrameResources.push_back(std::make_unique<FrameResource>(md3dDevice.Get(),
  721.             2, (UINT)mAllRitems.size(), (UINT)mMaterials.size()));
  722.     }
  723. }
  724.  
  725. void BezierPatchApp::BuildMaterials()
  726. {
  727.     auto whiteMat = std::make_unique<Material>();
  728.     whiteMat->Name = "quadMat";
  729.     whiteMat->MatCBIndex = 0;
  730.     whiteMat->DiffuseSrvHeapIndex = 3;
  731.     whiteMat->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  732.     whiteMat->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
  733.     whiteMat->Roughness = 0.5f;
  734.  
  735.     mMaterials["whiteMat"] = std::move(whiteMat);
  736. }
  737.  
  738. void BezierPatchApp::BuildRenderItems()
  739. {
  740.     auto quadPatchRitem = std::make_unique<RenderItem>();
  741.     quadPatchRitem->World = MathHelper::Identity4x4();
  742.     quadPatchRitem->TexTransform = MathHelper::Identity4x4();
  743.     quadPatchRitem->ObjCBIndex = 0;
  744.     quadPatchRitem->Mat = mMaterials["whiteMat"].get();
  745.     quadPatchRitem->Geo = mGeometries["quadpatchGeo"].get();
  746.     quadPatchRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST;
  747.     quadPatchRitem->IndexCount = quadPatchRitem->Geo->DrawArgs["quadpatch"].IndexCount;
  748.     quadPatchRitem->StartIndexLocation = quadPatchRitem->Geo->DrawArgs["quadpatch"].StartIndexLocation;
  749.     quadPatchRitem->BaseVertexLocation = quadPatchRitem->Geo->DrawArgs["quadpatch"].BaseVertexLocation;
  750.     mRitemLayer[(int)RenderLayer::Opaque].push_back(quadPatchRitem.get());
  751.     
  752.     mAllRitems.push_back(std::move(quadPatchRitem));
  753. }
  754.  
  755. void BezierPatchApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
  756. {
  757.     UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  758.     UINT matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));
  759.  
  760.     auto objectCB = mCurrFrameResource->ObjectCB->Resource();
  761.     auto matCB = mCurrFrameResource->MaterialCB->Resource();
  762.  
  763.     // For each render item...
  764.     for(size_t i = 0; i < ritems.size(); ++i)
  765.     {
  766.         auto ri = ritems[i];
  767.  
  768.         cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
  769.         cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
  770.         cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
  771.  
  772.         CD3DX12_GPU_DESCRIPTOR_HANDLE tex(mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
  773.         tex.Offset(ri->Mat->DiffuseSrvHeapIndex, mCbvSrvDescriptorSize);
  774.  
  775.         D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
  776.         D3D12_GPU_VIRTUAL_ADDRESS matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex*matCBByteSize;
  777.  
  778.         cmdList->SetGraphicsRootDescriptorTable(0, tex);
  779.         cmdList->SetGraphicsRootConstantBufferView(1, objCBAddress);
  780.         cmdList->SetGraphicsRootConstantBufferView(3, matCBAddress);
  781.  
  782.         cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
  783.     }
  784. }
  785.  
  786. std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> BezierPatchApp::GetStaticSamplers()
  787. {
  788.     // Applications usually only need a handful of samplers.  So just define them all up front
  789.     // and keep them available as part of the root signature.  
  790.  
  791.     const CD3DX12_STATIC_SAMPLER_DESC pointWrap(
  792.         0, // shaderRegister
  793.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  794.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  795.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  796.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  797.  
  798.     const CD3DX12_STATIC_SAMPLER_DESC pointClamp(
  799.         1, // shaderRegister
  800.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  801.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  802.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  803.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  804.  
  805.     const CD3DX12_STATIC_SAMPLER_DESC linearWrap(
  806.         2, // shaderRegister
  807.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  808.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  809.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  810.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  811.  
  812.     const CD3DX12_STATIC_SAMPLER_DESC linearClamp(
  813.         3, // shaderRegister
  814.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  815.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  816.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  817.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  818.  
  819.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicWrap(
  820.         4, // shaderRegister
  821.         D3D12_FILTER_ANISOTROPIC, // filter
  822.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  823.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  824.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressW
  825.         0.0f,                             // mipLODBias
  826.         8);                               // maxAnisotropy
  827.  
  828.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicClamp(
  829.         5, // shaderRegister
  830.         D3D12_FILTER_ANISOTROPIC, // filter
  831.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  832.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  833.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressW
  834.         0.0f,                              // mipLODBias
  835.         8);                                // maxAnisotropy
  836.  
  837.     return { 
  838.         pointWrap, pointClamp,
  839.         linearWrap, linearClamp, 
  840.         anisotropicWrap, anisotropicClamp };
  841. }
  842.